package handler

import (
	"account-service/models"
	"account-service/tools"
	"context"
	"math"
	"strconv"
	"strings"
	"time"

	pbAuth "account-service/proto/auth"
	pbParams "account-service/proto/params"
	pbResult "account-service/proto/result"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

/*
 +----------------------------------------------------------------------
 + Title        : AuthHandler
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2019-08-08
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : 权限处理
 +----------------------------------------------------------------------
*/

type AuthHandler struct {
	pbAuth.UnimplementedAuthSrvServer
}

/**
 * 新增权限
 *
 * @param uint32 Pid ----------------------------------非必传,父类ID
 * @param uint32 Id -----------------------------------非必传,角色ID
 * @param string Name ---------------------------------必传,名称
 * @param string ControllerName -----------------------非必传,控制器名称
 * @param string ActionName ---------------------------非必传,操作方法名称
 * @param int32 IsMenu --------------------------------非必传,是否菜单
 * @param int32 Status --------------------------------非必传,状态
 * @param string Note ---------------------------------非必传,备注
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *AuthHandler) AddAuth(ctx context.Context, req *pbAuth.AddAuthRequest) (*pbResult.Result, error) {
	if req.Name == "" {
		return nil, status.Errorf(codes.InvalidArgument, "请输入名称")
	}

	//判断名称是否存在【唯一性】
	var total int64
	err := models.Auth{}.GetTotalByParams(&models.Auth{}, &total, map[string]interface{}{
		"name":        req.Name,
		"status <> ?": -2,
	})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if total > 0 {
		return nil, status.Errorf(codes.Aborted, "权限名称已经存在")
	}

	i, err := models.Auth{}.Add(&models.Auth{
		Pid:            uint16(req.Pid),
		Name:           req.Name,
		ControllerName: req.ControllerName,
		ActionName:     req.ActionName,
		IsMenu:         int8(req.IsMenu),
		Note:           req.Note,
		Status:         int8(req.Status),
	})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if i <= 0 {
		return nil, status.Errorf(codes.Aborted, "新增权限失败")
	}

	return &pbResult.Result{Code: 200, Msg: "新增权限成功"}, nil
}

/**
 * 删除权限
 *
 * @param string Ids ----------------------------------必传,权限ID,支持多个
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *AuthHandler) DeleteAuth(ctx context.Context, req *pbParams.IdsRequest) (*pbResult.Result, error) {
	if req.Ids == "" {
		return nil, status.Errorf(codes.InvalidArgument, "权限ID错误")
	}

	//判断当前权限是否绑定角色
	authIds := tools.IntSplit(strings.TrimRight(req.Ids, ","), ",")

	var total int64
	err := models.RoleAuth{}.GetTotalByParams(&models.RoleAuth{}, &total, map[string]interface{}{
		"auth_id IN (?)": authIds,
	})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if total > 0 {
		return nil, status.Errorf(codes.Aborted, "当前权限已绑定角色,不允许删除")
	}

	result, err := models.Auth{}.EditByParams(&models.Auth{}, map[string]interface{}{
		"status":      -2,
		"update_time": time.Now(),
	}, map[string]interface{}{"id IN (?)": authIds})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if result <= 0 {
		return nil, status.Errorf(codes.Aborted, "删除权限失败")
	}

	return &pbResult.Result{Code: 200, Msg: "删除权限成功"}, nil
}

/**
 * 编辑权限
 *
 * @param uint32 Id -----------------------------------必传,权限ID
 * @param string Pid ----------------------------------必传,父类ID
 * @param string Name ---------------------------------必传,名称
 * @param string ControllerName -----------------------非必传,控制器名称
 * @param string ActionName ---------------------------非必传,操作方法名称
 * @param string IsMenu -------------------------------非必传,是否菜单
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *AuthHandler) EditAuth(ctx context.Context, req *pbAuth.EditAuthRequest) (*pbResult.Result, error) {
	if req.Id <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "权限ID错误")
	}

	params := map[string]interface{}{
		"controller_name": req.ControllerName,
		"action_name":     req.ActionName,
		"update_time":     time.Now(),
	}
	if req.Pid != "all" {
		i, _ := strconv.Atoi(req.Pid)
		params["pid"] = i
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsMenu != "all" {
		i, _ := strconv.Atoi(req.IsMenu)
		params["is_menu"] = i
	}
	if req.Note != "" {
		params["note"] = req.Note
	}

	//判断角色名称是否存在【唯一性】
	if req.Name != "" {
		var total int64
		err := models.Auth{}.GetTotalByParams(&models.Auth{}, &total, map[string]interface{}{
			"name":        req.Name,
			"status <> ?": -2,
			"id <> ?":     req.Id,
		})
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
		if total > 0 {
			return nil, status.Errorf(codes.Aborted, "权限名称已经存在")
		}
	}

	//编辑
	i, err := models.Auth{}.EditByPrimaryKey(&models.Auth{}, params, req.Id)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if i <= 0 {
		return nil, status.Errorf(codes.Aborted, "编辑权限失败")
	}

	return &pbResult.Result{Code: 200, Msg: "编辑权限成功"}, nil
}

/**
 * 编辑权限状态
 *
 * @param string Ids ----------------------------------必传,权限Id支持多个
 * @param int32 Status --------------------------------必传,状态
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *AuthHandler) EditAuthStatus(ctx context.Context, req *pbParams.EditStatusRequest) (*pbResult.Result, error) {
	if req.Ids == "" {
		return nil, status.Errorf(codes.InvalidArgument, "权限ID错误")
	}
	if !tools.IsContainNumber([]int{-1, 1}, int(req.Status)) {
		return nil, status.Errorf(codes.InvalidArgument, "权限状态错误")
	}

	authIds := tools.IntSplit(strings.TrimRight(req.Ids, ","), ",")

	if req.Status == -1 {
		var total int64
		err := models.RoleAuth{}.GetTotalByParams(&models.RoleAuth{}, &total, map[string]interface{}{
			"auth_id IN (?)": authIds,
		})
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
		if total > 0 {
			return nil, status.Errorf(codes.Aborted, "当前权限已绑定角色,不允许禁用")
		}
	}

	result, err := models.Auth{}.EditByParams(&models.Auth{}, map[string]interface{}{
		"status":      req.Status,
		"update_time": time.Now(),
	}, map[string]interface{}{"id IN (?)": authIds})
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	message := ""
	if req.Status == 1 {
		message = "启用权限"
	} else {
		message = "禁用权限"
	}
	if result <= 0 {
		return nil, status.Errorf(codes.Aborted, message+"失败")
	}

	return &pbResult.Result{Code: 200, Msg: message + "成功"}, nil
}

/**
 * 权限详情
 *
 * @param uint64 Id -----------------------------------必传,权限ID
 * @return *pbAuth.AuthDetailResponse, error
 * @author huwl
 */
func (e *AuthHandler) AuthDetail(ctx context.Context, req *pbParams.DetailRequest) (*pbAuth.AuthDetailResponse, error) {
	if req.Id <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "权限ID错误")
	}

	//获取权限信息
	auth := models.Auth{}
	result, err := models.Auth{}.GetResultByPrimaryKey(&auth, req.Id)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if result <= 0 || auth.Status == -2 {
		return nil, status.Errorf(codes.Aborted, "权限信息错误")
	}

	return &pbAuth.AuthDetailResponse{
		Auth: &pbAuth.Auth{
			Id:             uint32(auth.Id),
			Pid:            uint32(auth.Pid),
			Name:           auth.Name,
			ControllerName: auth.ControllerName,
			ActionName:     auth.ActionName,
			IsMenu:         uint32(auth.IsMenu),
			Note:           auth.Note,
			Status:         int32(auth.Status),
			CreateTime:     auth.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime:     auth.UpdateTime.Format("2006-01-02 15:04:05"),
		},
	}, nil
}

/**
 * 获取单条权限数据
 *
 * @param string Name ---------------------------------非必传,名称
 * @param string Pid ----------------------------------非必传,父类ID
 * @param string IsMenu -------------------------------非必传,是否菜单
 * @param string Status -------------------------------非必传,状态
 * @return *pbAuth.AuthDetailResponse, error
 * @author huwl
 */
func (e *AuthHandler) Row(ctx context.Context, req *pbAuth.QueryAuthRequest) (*pbAuth.AuthDetailResponse, error) {
	params := map[string]interface{}{}
	if req.Pid != "all" {
		i, _ := strconv.Atoi(req.Pid)
		params["pid"] = i
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsMenu != "all" {
		i, _ := strconv.Atoi(req.IsMenu)
		params["is_menu"] = i
	}
	if req.Status != "all" {
		params["status"] = req.Status
	}

	auth := models.Auth{}
	i, err := models.Auth{}.Row(&models.Auth{}, &auth, params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if i <= 0 || auth.Status == -2 {
		return nil, status.Errorf(codes.Aborted, "权限信息错误")
	}

	return &pbAuth.AuthDetailResponse{
		Auth: &pbAuth.Auth{
			Id:             uint32(auth.Id),
			Pid:            uint32(auth.Pid),
			Name:           auth.Name,
			ControllerName: auth.ControllerName,
			ActionName:     auth.ActionName,
			IsMenu:         uint32(auth.IsMenu),
			Note:           auth.Note,
			Status:         int32(auth.Status),
			CreateTime:     auth.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime:     auth.UpdateTime.Format("2006-01-02 15:04:05"),
		},
	}, nil
}

/**
 * 根據多個角色ID獲取权限
 *
 * @param string ids ----------------------------------必传,权限ID,过个
 * @return *pbAuth.AuthesResponse, error
 * @author huwl
 */
func (e *AuthHandler) Rows(ctx context.Context, req *pbParams.IdsRequest) (*pbAuth.AuthesResponse, error) {
	authIds := []interface{}{}
	ids := strings.Split(req.Ids, ",")
	for _, id := range ids {
		authIds = append(authIds, id)
	}

	auths := []models.Auth{}
	err := models.Auth{}.Rows(&auths, authIds)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	authItems := []*pbAuth.Auth{}
	for _, auth := range auths {
		authItems = append(authItems, &pbAuth.Auth{
			Id:             uint32(auth.Id),
			Pid:            uint32(auth.Pid),
			Name:           auth.Name,
			ControllerName: auth.ControllerName,
			ActionName:     auth.ActionName,
			IsMenu:         uint32(auth.IsMenu),
			Note:           auth.Note,
			Status:         int32(auth.Status),
			CreateTime:     auth.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime:     auth.UpdateTime.Format("2006-01-02 15:04:05"),
		})
	}

	return &pbAuth.AuthesResponse{
		Authes: authItems,
	}, nil
}

/**
 * 权限列表
 *
 * @param uint32 Id -----------------------------------非必传,权限ID
 * @param string Ids ----------------------------------非必传,权限ID,支持多个
 * @param string Pid ----------------------------------非必传,父类ID
 * @param string Name ---------------------------------非必传,名称
 * @param string IsMenu -------------------------------非必传,是否管理员
 * @param string Status -------------------------------非必传,状态支持多个：1,-1
 * @param string StartCreateTime ----------------------非必传,开始创建时间
 * @param string EndCreateTime ------------------------非必传,结束创建时间
 * @param string SortType -----------------------------非必传,排序方式
 * @param string SortField ----------------------------非必传,排序字段
 * @param int32 PageSize ------------------------------非必传,条数
 * @param int32 Page ----------------------------------非必传,页码
 * @return *pbAuth.AuthListResponse, error
 * @author huwl
 */
func (e *AuthHandler) AuthList(ctx context.Context, req *pbAuth.AuthListRequest) (*pbAuth.AuthListResponse, error) {
	params := map[string]interface{}{
		"status <> ?": -2,
	}
	if req.Id > 0 {
		params["id"] = req.Id
	}
	if req.Ids != "" {
		params["id in (?)"] = tools.IntSplit(req.Ids, ",")
	}
	if req.Pid != "all" {
		i, _ := strconv.Atoi(req.Pid)
		params["pid"] = i
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsMenu != "all" {
		i, _ := strconv.Atoi(req.IsMenu)
		params["is_menu"] = i
	}
	if req.Status != "all" {
		params["status in (?)"] = tools.IntSplit(req.Status, ",")
	}
	if req.StartCreateTime != "" {
		params["create_time >= ?"] = req.StartCreateTime + " 00:00:00"
	}
	if req.EndCreateTime != "" {
		params["create_time <= ?"] = req.EndCreateTime + " 23:59:59"
	}
	if req.SortField == "" {
		req.SortField = "id"
	}
	if req.SortType == "" {
		req.SortType = "desc"
	}
	if req.PageSize == 0 {
		req.PageSize = 20
	}
	if req.Page == 0 {
		req.Page = 1
	}

	//获取权限数量
	var total int64
	err := models.Auth{}.GetTotalByParams(&models.Auth{}, &total, params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	//获取权限数据
	authes := []models.Auth{}
	if total > 0 {
		err = models.Auth{}.GetResultsByParams(&models.Auth{}, &authes, params, int(req.Page), int(req.PageSize), req.SortField+" "+req.SortType)
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
	}

	//组装权限数据
	authItems := []*pbAuth.Auth{}
	for _, auth := range authes {
		authItems = append(authItems, &pbAuth.Auth{
			Id:             uint32(auth.Id),
			Pid:            uint32(auth.Pid),
			Name:           auth.Name,
			ControllerName: auth.ControllerName,
			ActionName:     auth.ActionName,
			IsMenu:         uint32(auth.IsMenu),
			Note:           auth.Note,
			Status:         int32(auth.Status),
			CreateTime:     auth.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime:     auth.UpdateTime.Format("2006-01-02 15:04:05"),
		})
	}

	pageTotal := math.Ceil(float64(total) / float64(req.PageSize))
	return &pbAuth.AuthListResponse{
		Authes: authItems,
		ListResult: &pbResult.ListCommonResult{
			Page:      uint32(req.Page),
			Total:     uint32(total),
			PageSize:  uint32(req.PageSize),
			PageTotal: uint32(pageTotal),
		},
	}, nil
}

/**
 * 权限数量
 *
 * @param uint32 Id -----------------------------------非必传,权限Id
 * @param string Ids ----------------------------------非必传,权限Id,支持多个
 * @param string Pid ----------------------------------非必传,父类Id
 * @param string Name ---------------------------------非必传,名称
 * @param string IsMenu -------------------------------非必传,是否管理员
 * @param string Status -------------------------------非必传,状态支持多个：1,-1
 * @param string StartCreateTime ----------------------非必传,开始创建时间
 * @param string EndCreateTime ------------------------非必传,结束创建时间
 * @return *pbResult.TotalResult, error
 * @author huwl
 */
func (e *AuthHandler) AuthTotal(ctx context.Context, req *pbAuth.AuthListRequest) (*pbResult.TotalResult, error) {
	params := map[string]interface{}{
		"status <> ?": -2,
	}
	if req.Id > 0 {
		params["id"] = req.Id
	}
	if req.Ids != "" {
		params["id in (?)"] = tools.IntSplit(req.Ids, ",")
	}
	if req.Pid != "all" {
		i, _ := strconv.Atoi(req.Pid)
		params["pid"] = i
	}
	if req.Name != "" {
		params["name"] = req.Name
	}
	if req.IsMenu != "all" {
		i, _ := strconv.Atoi(req.IsMenu)
		params["is_menu"] = i
	}
	if req.Status != "all" {
		params["status in (?)"] = tools.IntSplit(req.Status, ",")
	}
	if req.StartCreateTime != "" {
		params["create_time >= ?"] = req.StartCreateTime + " 00:00:00"
	}
	if req.EndCreateTime != "" {
		params["create_time <= ?"] = req.EndCreateTime + " 23:59:59"
	}

	//获取权限数量
	var total int64
	err := models.Auth{}.GetTotalByParams(&models.Auth{}, &total, params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	return &pbResult.TotalResult{Total: uint32(total)}, nil
}

/**
 * 绑定角色【绑定 + 取消绑定功能聚合一起】
 *
 * @param uint32 AuthId -------------------------------必传,权限ID
 * @param string RoleIds ------------------------------非必传,角色ID支持多个
 * @return *pbResult.Result, error
 * @author huwl
 */
func (e *AuthHandler) BindRole(ctx context.Context, req *pbAuth.BindRoleRequest) (*pbResult.Result, error) {
	roleIds := strings.TrimRight(req.RoleIds, ",")

	if req.AuthId <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "权限ID错误")
	}

	//获取该权限的权限
	roleAuthes := []models.RoleAuth{}
	err := models.RoleAuth{}.GetResultsByParams(&models.RoleAuth{}, &roleAuthes, map[string]interface{}{"auth_id": req.AuthId}, 1, -1, "id desc")
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	if len(roleAuthes) > 0 {
		//先删除
		result, err := models.RoleAuth{}.DeleteByParams(&models.RoleAuth{}, map[string]interface{}{"auth_id": req.AuthId})
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}
		if result <= 0 {
			return nil, status.Errorf(codes.Aborted, "绑定角色失败")
		}
	}

	if roleIds == "" {
		return &pbResult.Result{Code: 200, Msg: "绑定角色成功"}, nil
	}

	//后新增
	ids := tools.IntSplit(roleIds, ",")
	params := []models.RoleAuth{}
	for _, v := range ids {
		params = append(params, models.RoleAuth{
			AuthId: uint16(req.AuthId),
			RoleId: uint16(v),
		})
	}

	result, err := models.RoleAuth{}.Add(&params)
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}
	if result <= 0 {
		return nil, status.Errorf(codes.Aborted, "绑定角色失败")
	}

	return &pbResult.Result{Code: 200, Msg: "绑定角色成功"}, nil
}

/**
 * 获取树状权限
 *
 * @param string Pid --------------------------------必传,父分类ID
 * @param string Status -----------------------------非必传,状态支持多个
 * @return AuthTree error
 * @author huwl
 */
func (e *AuthHandler) GetTreeAuth(ctx context.Context, req *pbAuth.PidRequest) (*pbAuth.TreeAuthResult, error) {
	params := map[string]interface{}{
		"status <> ?": -2,
	}

	var pid int64
	if req.Pid != "all" {
		pid, _ = strconv.ParseInt(req.Pid, 10, 64)
		params["pid"] = pid
	}
	if req.Status != "all" {
		params["status IN (?)"] = strings.Split(strings.TrimRight(req.Status, ","), ",")
	}

	authes := []models.Auth{}
	err := models.Auth{}.GetResultsByParams(&authes, &authes, params, 1, -1, "id asc")
	if err != nil {
		return nil, status.Errorf(codes.Aborted, err.Error())
	}

	//获取子分类
	if req.IsChildrens == 1 {
		ids := []int{}
		for _, auth := range authes {
			ids = append(ids, int(auth.Id))
		}

		authItems := []models.Auth{}
		args := map[string]interface{}{
			"pid in (?)":  ids,
			"status <> ?": -2,
		}

		if req.Status != "all" {
			args["status IN (?)"] = strings.Split(strings.TrimRight(req.Status, ","), ",")
		}
		err := models.Auth{}.GetResultsByParams(&models.Auth{}, &authItems, args, 1, -1, "id asc")
		if err != nil {
			return nil, status.Errorf(codes.Aborted, err.Error())
		}

		authes = append(authes, authItems...)
	}

	authItems := []*pbAuth.Auth{}
	for _, auth := range authes {
		authItems = append(authItems, &pbAuth.Auth{
			Id:             uint32(auth.Id),
			Pid:            uint32(auth.Pid),
			Name:           auth.Name,
			ControllerName: auth.ControllerName,
			ActionName:     auth.ActionName,
			IsMenu:         uint32(auth.IsMenu),
			Status:         int32(auth.Status),
			Note:           auth.Note,
			CreateTime:     auth.CreateTime.Format("2006-01-02 15:04:05"),
			UpdateTime:     auth.UpdateTime.Format("2006-01-02 15:04:05"),
		})
	}

	trees := GenerateTree(authItems, uint32(pid), 0)
	return &pbAuth.TreeAuthResult{
		AuthTree: trees,
	}, nil
}

/**
 * 生成树
 *
 * @param []*pbAuth.Auth items ----------------------必传,权限
 * @param uint32 pid --------------------------------必传,父分类ID
 * @param int32 depth -------------------------------必传,深度
 * @return []*pbAuth.TreeAuth
 * @author huwl
 */
func GenerateTree(items []*pbAuth.Auth, pid uint32, depth int32) []*pbAuth.TreeAuth {
	trees := make([]*pbAuth.TreeAuth, 0)
	for _, row := range items {
		if row.Pid == pid {
			t := &pbAuth.TreeAuth{
				Id:             row.Id,
				Pid:            row.Pid,
				Name:           row.Name,
				ControllerName: row.ControllerName,
				ActionName:     row.ActionName,
				IsMenu:         int32(row.IsMenu),
				Status:         row.Status,
				Depth:          depth,
				Note:           row.Note,
			}
			t.Children = GenerateTree(items, row.Id, depth+1)
			trees = append(trees, t)
		}
	}

	return trees
}
